﻿// <copyright file="Command.cs" company="Ucaya">
// </copyright>
// <author>Ucaya</author>

namespace Channel9Kinect.Input
{
    #region

    using System;
    using System.Windows.Input;

    #endregion

    /// <summary>
    ///   Command pattern implementation
    /// </summary>
    public class Command : ICommand
    {
        #region Constructors and Destructors

        public Command(Action executed, Func<bool> canExecute = null)
        {
            if (canExecute != null)
            {
                this.CanExecute += (snd, e) =>
                    {
                        if (canExecute != null)
                        {
                            e.CanExecute = canExecute();
                        }
                    };
            }

            if (executed != null)
            {
                this.Executed += (snd, e) => executed();
            }
        }

        public Command(Action<object> executed, Func<object, bool> canExecute = null)
        {
            if (canExecute != null)
            {
                this.CanExecute += (snd, e) =>
                    {
                        if (canExecute != null)
                        {
                            e.CanExecute = canExecute(e.Parameter);
                        }
                    };
            }

            if (executed != null)
            {
                this.Executed += (snd, e) => executed(e.Parameter);
            }
        }

        #endregion

        #region Public Events

        /// <summary>
        ///   Check if the specified command can be executed.
        /// </summary>
        public event EventHandler<CanExecuteEventArgs> CanExecute;

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        /// <summary>
        ///   Occurs when the command is executed.
        /// </summary>
        public event EventHandler<ExecutedEventArgs> Executed;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets the name of the command.
        /// </summary>
        /// <value>the name of the command.</value>
        public string Name { get; private set; }

        #endregion

        #region Public Methods

        /// <summary>
        ///   Executes the command
        /// </summary>
        public virtual void Execute()
        {
            this.Execute(null);
        }

        /// <summary>
        ///   Executes the command
        /// </summary>
        /// <param name = "parameter">The parameter.</param>
        public virtual void Execute(object parameter)
        {
            if (this.Executed != null)
            {
                var e = new ExecutedEventArgs(this, parameter);
                this.Executed(this, e);
            }
        }

        /// <summary>
        ///   Raises the can execute event.
        /// </summary>
        /// <param name = "parameter">The parameter.</param>
        /// <returns>returns <c>true</c> if the command can be executed, otherwise <c>false</c>.</returns>
        public virtual bool RaiseCanExecute(object parameter)
        {
            bool result = true;
            if (this.CanExecute != null)
            {
                var e = new CanExecuteEventArgs(this, parameter);
                this.CanExecute(this, e);
                result = e.CanExecute;
            }

            return result;
        }

        #endregion

        #region Explicit Interface Methods

        bool ICommand.CanExecute(object parameter)
        {
            return this.RaiseCanExecute(parameter);
        }

        #endregion
    }

    public class Command<T> : ICommand
    {
        #region Constructors and Destructors

        public Command()
        {
        }

        public Command(Action<T> executed = null, Func<T, bool> canExecute = null)
        {
            if (canExecute != null)
            {
                this.CanExecute += (snd, e) =>
                    {
                        if (canExecute != null)
                        {
                            e.CanExecute = canExecute(e.Parameter);
                        }
                    };
            }

            if (executed != null)
            {
                this.Executed += (snd, e) => executed(e.Parameter);
            }
        }

        #endregion

        #region Public Events

        /// <summary>
        ///   Check if the specified command can be executed.
        /// </summary>
        public event EventHandler<CanExecuteEventArgs<T>> CanExecute;

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        /// <summary>
        ///   Occurs when the command is executed.
        /// </summary>
        public event EventHandler<ExecutedEventArgs<T>> Executed;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets the name of the command.
        /// </summary>
        /// <value>the name of the command.</value>
        public string Name { get; private set; }

        #endregion

        #region Public Methods

        /// <summary>
        ///   Executes the command
        /// </summary>
        /// <param name = "parameter">The parameter.</param>
        public virtual void Execute(T parameter)
        {
            if (this.Executed != null)
            {
                this.Executed(this, new ExecutedEventArgs<T>(this, parameter));
            }
        }

        /// <summary>
        ///   Raises the can execute event.
        /// </summary>
        /// <param name = "parameter">The parameter.</param>
        /// <returns>returns <c>true</c> if the command can be executed, otherwise <c>false</c>.</returns>
        public virtual bool RaiseCanExecute(T parameter)
        {
            bool result = true;
            if (this.CanExecute != null)
            {
                var e = new CanExecuteEventArgs<T>(this, parameter);
                this.CanExecute(this, e);
                result = e.CanExecute;
            }

            return result;
        }

        #endregion

        #region Explicit Interface Methods

        bool ICommand.CanExecute(object parameter)
        {
            if (parameter != null && !typeof(T).IsAssignableFrom(parameter.GetType()))
            {
                throw new ArgumentException("parameter is not cannot be converter to (" + typeof(T) + ")", "parameter");
            }
            T prm = default(T);
            if (parameter != null)
            {
                prm = (T)parameter;
            }

            return this.RaiseCanExecute(prm);
        }

        void ICommand.Execute(object parameter)
        {
            if (parameter != null && !typeof(T).IsAssignableFrom(parameter.GetType()))
            {
                throw new ArgumentException("parameter is not cannot be converter to (" + typeof(T) + ")", "parameter");
            }
            T prm = default(T);
            if (parameter != null)
            {
                prm = (T)parameter;
            }

            this.Execute(prm);
        }

        #endregion
    }
}